//
// MessageBox.h
// Usage: Process message box. For IPC.
// CreateDate: 2009-05-15
// Author: MaJiuyue
//
// Line83: free() need fix: when message from user, do not need free
//
#include <string.h>
#include "MessageBox.h"
#include "../schedule/Process.h"

MessageBox::MessageBox(int capacity)
	: umbox_size(capacity), bWait(false), wait_pid(PID_ANY)
{
}

MessageBox::MessageBox(const MessageBox &target)
	: umbox_size(target.umbox_size), bWait(false), wait_pid(PID_ANY)
{
}

MessageBox::~MessageBox()
{
	// Clear queue
	for(int i=0; i<MQUEUE_SIZE; i++)
		for(int j=0; j<mqueue[i].getLength(); j++)
			mqueue[i].removeFirst();
}

bool MessageBox::PutMessage(MQUEUE_TYPE type, MESSAGE *msg)
{
	// if target mbox is USR_MBOX, check if exceed capacity
	if(type==USR_MBOX)
		if(mqueue[USR_MBOX].getLength()>=umbox_size)
			return false;

	// Now can put message
	mqueue[type].insertLast(msg);
	
	return true;
}

bool MessageBox::GetMessage(pid_t pid, MESSAGE *msg)
{
	MESSAGE *src = NULL;

	// Get and remove message from mqueue
	for(int i=0; i<MQUEUE_SIZE; i++)
	{
		if((mqueue[i].getLength()!=0) && (pid==PID_ANY))
		{
			src = mqueue[i].removeFirst();
			break;
		}
		else if((mqueue[i].getLength()!=0) && (pid!=PID_ANY))
		{
			mqueue[i].iterateFirst();
			while(mqueue[i].iterateIsValid())
			{
				src = mqueue[i].iterateGetValue();
				if(src->pid == pid)
				{
					mqueue[i].remove();
					break;
				}
				mqueue[i].iterateNext();
			}
			src = NULL;
		}
	}
	
	// if empty, return false
	if(src==NULL)
	{
		bWait = true;
		wait_pid = pid;
		wait_buf = msg;
		return false;
	}

	// if queue not empty, copy message
	memcpy(msg, src, src->size);

	//free(src);
	
	return true;
}

bool MessageBox::IsFull()
{
	return (mqueue[USR_MBOX].getLength()==umbox_size);
}

bool MessageBox::IsEmpty()
{
	for(int i=0; i<MQUEUE_SIZE; i++)
		if(mqueue[MQUEUE_SIZE].getLength()!=0)
			return false;
	return true;
}

bool MessageBox::IsWaitingFor(pid_t pid)
{
	return (bWait && ((wait_pid==PID_ANY) || (wait_pid==pid)));
}

void MessageBox::ResetWait()
{
	bWait = false;
}

void MessageBox::ClearBox()
{
}

